package tech.yunqian.slim.project.service;

import java.math.BigDecimal;
import java.math.RoundingMode;

import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;
import tech.yunqian.slim.project.enums.ComparisonOperator;
import tech.yunqian.slim.project.enums.DataType;

@Slf4j
@Service
public class ComparisonService {
    public static BigDecimal cutValue(String valueString, String stepString) {
        BigDecimal value = new BigDecimal(valueString);
        if (!stepString.isBlank()) {
            BigDecimal step = new BigDecimal(stepString);
            Integer scale = step.scale();
            value = value.divide(step).setScale(scale, RoundingMode.HALF_EVEN).multiply(step).setScale(scale, RoundingMode.HALF_EVEN);
        }
        return value;
    }

    private static Boolean evaluateBool(String value, String threshold, ComparisonOperator comparisonOperator) {
        Boolean result = null;
        Boolean boolValue = Boolean.parseBoolean(value);
        Boolean boolThreshold = Boolean.parseBoolean(threshold);
        if (comparisonOperator.equals(ComparisonOperator.EQUAL)) {
            result = boolValue.equals(boolThreshold);
        } else if (comparisonOperator.equals(ComparisonOperator.NOT_EQUAL)) {
            result = !boolValue.equals(boolThreshold);
        }
        return result;
    }

    private static Boolean evaluateNumber(String value, String threshold, String step, ComparisonOperator comparisonOperator) {
        Boolean result = null;
        BigDecimal bdValue = null;
        BigDecimal bdThreshold = null;
        if (step == null) {
            bdValue = new BigDecimal(value);
            bdThreshold = new BigDecimal(threshold);
        } else {
            bdValue = cutValue(value, step);
            bdThreshold = cutValue(threshold, step);
        }
        if (comparisonOperator.equals(ComparisonOperator.LESS_THAN)) {
            result = bdValue.compareTo(bdThreshold) < 0;
        } else if (comparisonOperator.equals(ComparisonOperator.LESS_EQUAL)) {
            result = bdValue.compareTo(bdThreshold) <= 0;
        } else if (comparisonOperator.equals(ComparisonOperator.EQUAL)) {
            result = bdValue.compareTo(bdThreshold) == 0;
        } else if (comparisonOperator.equals(ComparisonOperator.NOT_EQUAL)) {
            result = bdValue.compareTo(bdThreshold) != 0;
        } else if (comparisonOperator.equals(ComparisonOperator.GREATER_EQUAL)) {
            result = bdValue.compareTo(bdThreshold) >= 0;
        } else if (comparisonOperator.equals(ComparisonOperator.GREARER_THAN)) {
            result = bdValue.compareTo(bdThreshold) > 0;
        }
        return result;
    }

    public static Boolean evaluate(String value, String threshold, String step, DataType dataType, ComparisonOperator comparisonOperator) {
        Boolean result = null;
        try {
            if (dataType.equals(DataType.STRING)) {
                result = value.equals(threshold);
            } else if (dataType.equals(DataType.BOOL)) {
                result = evaluateBool(value, threshold, comparisonOperator);
            } else if (dataType.equals(DataType.INT32)) {
                result = evaluateNumber(value, threshold, step, comparisonOperator);
            } else if (dataType.equals(DataType.INT64)) {
                result = evaluateNumber(value, threshold, step, comparisonOperator);
            } else if (dataType.equals(DataType.FLOAT)) {
                result = evaluateNumber(value, threshold, step, comparisonOperator);
            } else if (dataType.equals(DataType.DOUBLE)) {
                result = evaluateNumber(value, threshold, step, comparisonOperator);
            }
        } catch (Exception e) {
            log.info(e.getMessage());
            StackTraceElement[] traces = e.getStackTrace();
            for (StackTraceElement trace : traces) {
                log.debug(trace.toString());
            }
        }
        return result;
    }
}
